AWSアカウント間のDynamoDBデータ移行計画の記録(事象の回避とまとめ)
はじめに
随分間が空いてしまいました。
想定外の事象の原因についてとその回避策、そしてまとめ。これで最後です。
前回まで
3 回にわたって手法の検証、計画の作成、実施について記載しました。
- AWSアカウント間のS3, DynamoDBデータ移行計画の記録 (背景と転送方法の検討)
- AWSアカウント間のS3, DynamoDBデータ移行計画の記録(データ完全性検証方法の検討)
- AWSアカウント間のDynamoDBデータ移行計画の記録(計画の実行と想定外の事象)
今回は、実施時に発生した事象についての原因の説明と回避について記載します。
発生した事象について
おさらいになります。前回発生した事象から。
取り込みの Producer 及び転送用の Worker が想定以上に働いておらず、転送対象のテーブルの Write Capacity Unit が想定の 1/5 程度で頭打ちになってしまっていました。処理の並列度が低く、想定時間内に終わりません。
転送システムは以前示したとおりですが、再度記載しておきました。
原因について
原因について確認していきます。
この転送システムの Producer は転送元のダンプファイルの数によってスケールします。つまり、ダンプファイルが起動した Producer のコンテナ数よりも少なければ、当然ながら処理は最大までスケールしません。
S3 にストアされた転送対象のファイル数を確認したところ、以下のようになっていました。
- 重要データα のダンプデータ数: 30前後
- 重要データβ のダンプデータ数: 4
重要データ β のファイル数が圧倒的に足りません。これが転送ソリューションで処理がスケールしなかった原因です。
では、同じデータ件数のはずなのになぜこのような事態になったのでしょうか。
なぜ同じデータ件数なのに転送対象のファイル数が異なるのか
DynamoDB の Export to S3 の機能を利用し Export を実行すると、指定された S3 Bucket にダンプファイルが出力されます。
ファイルの詳細を確認すると JSON Line の形式で記述されたテキストファイルを gz で圧縮したものが、出力されている事がわかります。ファイルは一定のサイズでローリングされます。
「一定のサイズでローリングされます。」
これが大本の原因になります。少しずつ見ていきます。 以前データの特徴について記載していました。再度確認。
- 重要データα と重要データβ のデータサイズ比はおよそ 1 : 5
- 重要データβ はフラグが中心のデータである
重要データβ のほうがデータ量が少ない上、フラグが中心となっており、圧縮効率が非常に良いデータ(すなわち、圧縮した際に同じサイズでもより多くのデータ数が格納される)である可能性が高いです。
つまり、バックアップされたダンプファイルを gz 圧縮した場合、同じファイルサイズであっても、重要データβ のほうが一つの圧縮ファイルに含まれるデータ数が α と比較して多くなることが予想できます。
実際、圧縮ファイル内の JSON Line 数を確認してみると以下のような結果でした。
- 重要データα のデータ数は約 500,000 前後
- 重要データβ のデータ数は約 4,000,000 弱
軽く 7〜8 倍のデータ量の差があることがわかりました。
これはいけません。元々 600,000 前後のデータ数を想定して各種パラメータを調整していた(特に SQS の Visibility Timeout の設定等)ため、想定の数倍以上を処理できるように最適化していません。
ダンプファイル数による動作の違い
今回の転送ソリューションにおける Producer は SQS に入力された1つのダンプファイルの S3 の Location を 1 つの処理として実行しています。
つまり、重要データα は タスクの並列度<ダンプファイル数 の関係が成り立つため、並列度を最大まで生かして処理が実行できます。
対して重要データβ は タスクの並列度>>ダンプファイル数 の関係であるため、どんなに Producer が頑張って並列できるタスクを増やしたところで、処理対象となるダンプファイル数が圧倒的に少ないため、並列タスクの意味がありません。さらに 1 つのタスクが担当する対象のデータが圧倒的に多いため、処理実行時間が当初想定していたものを大幅に超えるということがわかりました。
当初の予定では Producer 1 タスクにつき、最速で15分。最悪25分で作業が完了できると想定しました。これは、全タスクが全て同時並列に実行した場合の想定です。そのため SQS の Message の Visivility を 30分に指定していました。この時間を超えてしまうと SQS のメッセージが見えてしまい、別のタスクがこのメッセージを処理し始めてしまいます。こうなるとすでに登録済みのデータを再処理することになります。並列度は低い上に処理する件数は同じであるため、想定時間をゆうに超えてしまうというのは、現場の実際のデータを投入して初めて気づきました。
雑な図を描くとこんな関係になります。ファイル数が極端に少ない場合、遊んでるタスクと超忙しいタスクが現れてしまい、適切に処理が分散されていません。
対応方法
状況から、ダンプされたファイル数と、中に記録されているレコード数が問題であるということがわかりました。幸いファイルの内容は単純な JSON Line 形式であり、集計情報等のメタデータがあるわけではないことがわかっていたため、単純に Split するだけで対応ができそうです。
Producer, Worker のタスク数は固定していたため、これらを最大限利用できるよう、タスク数と同等、もしくはそれ以上の数になるよう分割しました。
すでに正常に転送が完了している重要データ α の転送実績から、約 50 万件であれば 20 分前後で転送が完了できることがわかっています。したがって、最低でも 1 ファイル 50 万件以下になるようファイルを分割します。以下の手順で分割します。
- Split の対象となる gz ファイルを解凍
- JSON Line を 50 万件で Split
- Split したデータを gz で再圧縮
- 元々転送対象として監視している Bucket とは別の Bucket へファイルを転送(こちらの意図せず先に処理が走ってしまうのを避けるため)
分割方法
以下のコマンドで Split を実行しています。
$ split -l 500000 --numeric-suffixes hogehoge.json hogehoge_
hogehoge_
というファイル名に数値がついた形のファイルが作成されるため、拡張子 .json
を付与します。作業完了後は以下のようなファイルが作成されます。
wc -l ./*.json 500000 ./hogehoge_00.json 500000 ./hogehoge_01.json 500000 ./hogehoge_02.json 500000 ./hogehoge_03.json 500000 ./hogehoge_04.json 159670 ./hogehoge_05.json 500000 ./fugafuga_00.json 500000 ./fugafuga_01.json 500000 ./fugafuga_02.json 500000 ./fugafuga_03.json 500000 ./fugafuga_04.json 158079 ./fugafuga_05.json 500000 ./fizzbuzz_00.json 500000 ./fizzbuzz_01.json 500000 ./fizzbuzz_02.json 500000 ./fizzbuzz_03.json 500000 ./fizzbuzz_04.json 155535 ./fizzbuzz_05.json 500000 ./momonga_00.json 500000 ./momonga_01.json 500000 ./momonga_02.json 500000 ./momonga_03.json 500000 ./momonga_04.json 156151 ./momonga_05.json 10629435 合計
これらのファイルを S3 に格納し、再度 Producer へ処理を再実行します。
実際に実行したところ、処理の並列度が想定通りの値となり、1時間かかっても終わらなかったインポート作業は20分弱で完了しました。
反省点
転送対象のデータセットには、数種類あるのは事前に分かっていましたが、一番複雑かつデータ数の多いもののみを代表として、様々な計測を行っていました(大は小を兼ねるの思い込み)
しかし、データの種別によってデータ量が大きく異なること、これにより転送対象とするファイル数に大きく影響を与えるということが想定できていませんでした。
実際蓋を開けてみると、データのバリエーションによる転送対象ファイルの違いが転送処理のスケジュールに大きく影響を与える結果になりました。
今回の事象は準備段階における検証漏れによって引き起こされた、本来であれば事前に防げたはずの事象でした。動作検証の段階で、転送対象のデータの特性についてもう少し注意深く観察する必要がありました。
さらに今回は現場において、比較的リスクが少ないこと等が分かった上で、手順の修正をその場で行いました。たまたまうまくいったものの、正しいことではありません。想定外、計画外の事が発生した時点で私の負けです。 自戒をこめてここに記録します。
最後に
都元さん、あなたが残した大きな宿題の1つであった AWS アカウント引っ越し作業は様々な障害や調整を乗り越えてやり切りましたよ。
(半ば強制的に)渡されたバトンですがちゃんとゴールまで運びました。
都元さんがいなくなってからすでに 1 年半以上も経ってしまいましたが。
元々このプロジェクトは少し特殊な状況であり、お客様のシステム全体を把握及びメンテナンスできるメンバーが私のみでした。
これは私がプロジェクトの初期段階から関わっており、すでにほとんどのメンバーがプロジェクトを去ってしまったその時には、過去の経緯を含めて私しか知らない状態。さらに過去の経緯から様々なカスタマイズが加えられており、もはや私一人でカバーできる範囲も大きく超えていました。
そのため、根幹となるシステムの部分だけでも私以外がメンテナンスや障害対応できるよう、二人の柱を据えた体制を組みました。それが、わたしと元々プロジェクト当初のオリジナルメンバーである都元さんでした。この二人体制の間にこの AWS アカウント引っ越しプロジェクトが計画され、これらを主導するはずでした。
しかし、突然崩れた二人体制。
【訃報】シニアシステムアーキテクト 都元ダイスケの逝去に関するお知らせ
今でもあまり現実感が持てていない。結果として最後まで見届けられたのは私のみ。複雑な思いがあります。
このプロジェクトは様々な人の協力で完走できました、改めて感謝します。
実作業メンバーとして活躍してくれた Prismatix 事業部の林さん、横山くん。連携システムの改修を行い、当日の移行作業にも付き合ってくれた CX 部のみなさん、各連携システムの開発ベンダーの担当者の方。当然ながらシステムを利用いただいてるお客様の皆様。
そしてこのプロジェクトの初期構想から関わっていた都元さん。
本当にありがとうございました。
そしてお疲れ様でした。